import 'dart:async';

/**
 * 了解创建 流的方式
 *  await for 遍历流,'等待流主动发出'
 */
void main() async {
  // 1. Stream.fromIterable（同步地从一个 Iterable 中发出多个事件）
  print('1. Stream.fromIterable');
  await for (final value in Stream.fromIterable([1, 2, 3])) {
    print('fromIterable: $value');
  }

  // 2. Stream.value（只发出一个值，然后关闭）
  print('\n2. Stream.value');
  await for (final value in Stream.value(42)) {
    print('value: $value');
  }

  // 3. Stream.error（只发出一个错误，然后关闭）
  print('\n3. Stream.error');
  try {
    await for (final value in Stream.error('Something went wrong')) {
      print(value);
    }
  } catch (e) {
    print('Caught error: $e');
  }

  // 4. Stream.empty（创建一个什么都不发的空流）
  print('\n4. Stream.empty');
  await for (final value in Stream.empty()) {
    print('empty: $value'); // 不会输出
  }

  // 5. Stream.periodic（定期发送数据） take 发出 1 2 3
  print('\n5. Stream.periodic');
  final periodicStream = Stream.periodic(Duration(milliseconds: 500), (count) => count).take(3);
  await for (final value in periodicStream) {
    print('periodic: $value');
  }

  // 6. StreamController（手动控制数据流）
  /**
   * StreamController 是一个类，用于创建流。
   */
  print('\n6. StreamController');
  final controller = StreamController<String>();
  controller.stream.listen(
        (event) => print('controller: $event'),
    onDone: () => print('controller done'),
  );
  controller.add('hello');
  controller.add('world');
  controller.close();

  // 7. StreamController.broadcast（允许多订阅的广播流）
  print('\n7. StreamController.broadcast');
  final broadcastController = StreamController<int>.broadcast();

  broadcastController.stream.listen((data) => print('Listener 1: $data'));
  broadcastController.stream.listen((data) => print('Listener 2: $data'));

  broadcastController.add(1);
  broadcastController.add(2);
  broadcastController.close();

  // 8. async* 函数生成 Stream（最灵活方式）
  print('\n8. async* generator stream');
  await for (final value in generateStream()) {
    print('async*: $value');
  }
}

Stream<String> generateStream() async* {
  yield 'A';
  await Future.delayed(Duration(milliseconds: 200));
  yield 'B';
  yield 'C';
}